package common;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import server.rest.HttpContext;
import server.rest.ResponseException;

public final class ParamHelper
{

    public static String PADDING_ROWS = "rows";
    public static String PADDING_PAGE = "page";
    public static String PADDING_NEED_TOTAL = "needTotal";

    private ParamHelper()
    {
    }

    /**
     * Get a required string value from the URI, fail if the parameter is null/empty.
     * 
     * @param context the HTTP context.
     * @param name the name of the string parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static String getRequiredString(final HttpContext context, final String name) throws ResponseException
    {
        String value = context.getParameter(name);
        if ((null == value) || (true == value.isEmpty()))
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to acquire parameter: %s", name));
        }

        return value;
    }

    /**
     * Get a required string value from the query string, fail if the parameter is null/empty.
     * 
     * @param context the HTTP context.
     * @param name the name of the string parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static String getRequiredQueryString(final HttpContext context, final String name) throws ResponseException
    {
        String value = context.getRequest().getParameter(name);
        if ((null == value) || (true == value.isEmpty()))
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to acquire parameter: %s", name));
        }

        try
        {
            return URLDecoder.decode(value, "UTF-8");
        }
        catch (UnsupportedEncodingException e)
        {
            return value;
        }
    }

    /**
     * Get the value of an optional parameter from the query string.
     * 
     * @param context the HTTP context.
     * @param name the name of the string parameter to acquire.
     * @param defaultValue the default value to return if the parameter does not exist.
     * @return the value requested.
     */
    public static String getOptionalQueryString(final HttpContext context, final String name, final String defaultValue)
    {
        String value = getOptionalQueryString(context, name);
        if ((null == value) || (true == value.isEmpty()))
        {
            return defaultValue;
        }

        return value;
    }

    /**
     * Get the value of an optional parameter from the query string.
     * 
     * @param context the HTTP context.
     * @param name the name of the string parameter to acquire.
     * @param defaultValue the default value to return if the parameter does not exist.
     * @return the value requested.
     */
    public static String getOptionalQueryString(final HttpContext context, final String name)
    {
        return context.getRequest().getParameter(name);
    }

    /**
     * Get a required boolean value, if the value cannot be acquired/parsed then an exception is
     * thrown.
     * 
     * @param context the HTTP context.
     * @param name the name of the boolean parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static boolean getRequiredBoolean(final HttpContext context, final String name) throws ResponseException
    {
        String value = getRequiredString(context, name);

        try
        {
            return Boolean.parseBoolean(value);
        }
        catch (Exception e)
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to parse boolean parameter: %s", name));
        }
    }

    /**
     * Get a requiredboolean value, if the value cannot be parsed then an exception is thrown.
     * 
     * @param context the HTTP context.
     * @param name the name of the string to acquire.
     * @param defaultValue the default value to return if the parameter does not exist.
     * @return the value requested.
     */
    public static boolean getRequiredQueryBoolean(final HttpContext context, final String name)
                    throws ResponseException
    {
        String value = getRequiredQueryString(context, name);

        try
        {
            return Boolean.parseBoolean(value);
        }
        catch (Exception e)
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to parse boolean parameter: %s", name));
        }
    }

    /**
     * Get an optional boolean value, if the value cannot be parsed then the default value is
     * returned.
     * 
     * @param context the HTTP context.
     * @param name the name of the string to acquire.
     * @param defaultValue the default value to return if the parameter does not exist.
     * @return the value requested.
     */
    public static Boolean getOptionalQueryBoolean(final HttpContext context, final String name,
                    final Boolean defaultValue) throws ResponseException
    {
        String value = getOptionalQueryString(context, name, null);
        if (null != value)
        {
            try
            {
                return Boolean.parseBoolean(value);
            }
            catch (Exception e)
            {
                throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                    "Failed to parse boolean parameter: %s", name));
            }
        }

        return defaultValue;
    }

    /**
     * Get a required integer value, if the value cannot be acquired/parsed then an exception is
     * thrown.
     * 
     * @param context the HTTP context.
     * @param name the name of the integer parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static int getRequiredInt(final HttpContext context, final String name) throws ResponseException
    {
        String value = getRequiredString(context, name);

        try
        {
            return Integer.parseInt(value);
        }
        catch (NumberFormatException e)
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to parse integer parameter: %s", name));
        }
    }

    /**
     * Get a required integer value, if the value cannot be acquired/parsed then an exception is
     * thrown.
     * 
     * @param context the HTTP context.
     * @param name the name of the integer parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static int getRequiredQueryInt(final HttpContext context, final String name) throws ResponseException
    {
        String value = getRequiredQueryString(context, name);

        try
        {
            return Integer.parseInt(value);
        }
        catch (NumberFormatException e)
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to parse integer parameter: %s", name));
        }
    }

    /**
     * Get an optional integer value, if the value cannot be parsed then the default value is
     * returned.
     * 
     * @param context the HTTP context.
     * @param name the name of the string to acquire.
     * @param defaultValue the default value to return if the parameter does not exist.
     * @return the value requested.
     */
    public static Integer getOptionalQueryInt(final HttpContext context, final String name, final Integer defaultValue)
                    throws ResponseException
    {
        String value = getOptionalQueryString(context, name, null);
        if (null != value)
        {
            try
            {
                return Integer.parseInt(value);
            }
            catch (NumberFormatException e)
            {
                throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                    "Failed to parse integer parameter: %s", name));
            }
        }

        return defaultValue;
    }

    /**
     * Get a required long value, if the value cannot be acquired/parsed then an exception is
     * thrown.
     * 
     * @param context the HTTP context.
     * @param name the name of the long parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static long getRequiredLong(final HttpContext context, final String name) throws ResponseException
    {
        String value = getRequiredString(context, name);

        try
        {
            return Long.parseLong(value);
        }
        catch (NumberFormatException e)
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to parse long parameter: %s", name));
        }
    }

    /**
     * Get a required long value, if the value cannot be acquired/parsed then an exception is
     * thrown.
     * 
     * @param context the HTTP context.
     * @param name the name of the long parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static long getRequiredQueryLong(final HttpContext context, final String name) throws ResponseException
    {
        String value = getRequiredQueryString(context, name);

        try
        {
            return Long.parseLong(value);
        }
        catch (NumberFormatException e)
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to parse long parameter: %s", name));
        }
    }

    /**
     * Get an optional long value, if the value cannot be parsed then the default value is returned.
     * 
     * @param context the HTTP context.
     * @param name the name of the string to acquire.
     * @param defaultValue the default value to return if the parameter does not exist.
     * @return the value requested.
     */
    public static Long getOptionalQueryLong(final HttpContext context, final String name, final Long defaultValue)
                    throws ResponseException
    {
        String value = getOptionalQueryString(context, name, null);
        if (null != value)
        {
            try
            {
                return Long.parseLong(value);
            }
            catch (NumberFormatException e)
            {
                throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                    "Failed to parse long parameter: %s", name));
            }
        }

        return defaultValue;
    }

    /**
     * Get a required float value, if the value cannot be acquired/parsed then an exception is
     * thrown.
     * 
     * @param context the HTTP context.
     * @param name the name of the float parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static float getRequiredFloat(final HttpContext context, final String name) throws ResponseException
    {
        String value = getRequiredString(context, name);

        try
        {
            return Float.parseFloat(value);
        }
        catch (NumberFormatException e)
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to parse float parameter: %s", name));
        }
    }

    /**
     * Get a required float value, if the value cannot be acquired/parsed then an exception is
     * thrown.
     * 
     * @param context the HTTP context.
     * @param name the name of the float parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static float getRequiredQueryFloat(final HttpContext context, final String name) throws ResponseException
    {
        String value = getRequiredQueryString(context, name);

        try
        {
            return Float.parseFloat(value);
        }
        catch (NumberFormatException e)
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to parse float parameter: %s", name));
        }
    }

    /**
     * Get an optional float value, if the value cannot be parsed then the default value is
     * returned.
     * 
     * @param context the HTTP context.
     * @param name the name of the string to acquire.
     * @param defaultValue the default value to return if the parameter does not exist.
     * @return the value requested.
     */
    public static Float getOptionalQueryFloat(final HttpContext context, final String name, final Float defaultValue)
                    throws ResponseException
    {
        String value = getOptionalQueryString(context, name, null);
        if (null != value)
        {
            try
            {
                return Float.parseFloat(value);
            }
            catch (NumberFormatException e)
            {
                throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                    "Failed to parse float parameter: %s", name));
            }
        }

        return defaultValue;
    }

    /**
     * Get a required date value, if the value cannot be acquired/parsed then an exception is
     * thrown.
     * 
     * @param context the HTTP context.
     * @param name the name of the date parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static Date getRequiredDate(final HttpContext context, final String name) throws ResponseException
    {
        String value = getRequiredString(context, name);

        try
        {
            return DateTimeHelper.parseExact(value, DateTimeHelper.URI_DATEONLY);
        }
        catch (ParseException e)
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to parse date parameter: %s", name));
        }
    }

    /**
     * Get a required date value, if the value cannot be acquired/parsed then an exception is
     * thrown.
     * 
     * @param context the HTTP context.
     * @param name the name of the date parameter to acquire.
     * @return the value requested.
     * @throws ResponseException
     */
    public static Date getRequiredQueryDate(final HttpContext context, final String name) throws ResponseException
    {
        String value = getRequiredQueryString(context, name);

        try
        {
            return DateTimeHelper.parseExact(value, DateTimeHelper.URI_DATEONLY);
        }
        catch (ParseException e)
        {
            throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                "Failed to parse date parameter: %s", name));
        }
    }

    /**
     * Get an optional date value, if the value cannot be parsed then the default value is returned.
     * 
     * @param context the HTTP context.
     * @param name the name of the string to acquire.
     * @param defaultValue the default value to return if the parameter does not exist.
     * @return the value requested.
     */
    public static Date getOptionalQueryDate(final HttpContext context, final String name, final Date defaultValue)
                    throws ResponseException
    {
        String value = getOptionalQueryString(context, name, null);
        if (null != value)
        {
            try
            {
                return DateTimeHelper.parseExact(value, DateTimeHelper.URI_DATEONLY);
            }
            catch (ParseException e)
            {
                throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST, String.format(
                    "Failed to parse date parameter: %s", name));
            }
        }

        return defaultValue;
    }

    public static List<Integer> getOptionalParamIds(HttpContext context, String paramName) throws ResponseException
    {
        List<Integer> rez = new ArrayList<Integer>();
        String tmpValue = getOptionalQueryString(context, paramName, null);
        if (null != tmpValue)
        {
            String[] params = tmpValue.split(",");
            for (String param : params)
            {
                if (param != null && !param.trim().isEmpty())
                {
                    try
                    {
                        rez.add(Integer.parseInt(param));
                    }
                    catch (NumberFormatException e)
                    {
                        throw new ResponseException(HttpServletResponse.SC_BAD_REQUEST,
                                        "Failed to parse integer parameter: " + paramName);
                    }
                }
            }
        }

        return rez;
    }

    public static String getHeader(HttpContext context, String headerName)
    {
        return context.getRequest().getHeader(headerName);
    }

    public static String getCookieValue(HttpContext context, String cookieKey)
    {
        for (Cookie coo : context.getRequest().getCookies())
        {
            if (coo.getName().equalsIgnoreCase(cookieKey))
            {
                return coo.getValue();
            }
        }
        return null;
    }

}
